home *** CD-ROM | disk | FTP | other *** search
/ Clickx 115 / Clickx 115.iso / software / tools / windows / tails-i386-0.16.iso / live / filesystem.squashfs / usr / lib / ruby / 1.8 / resolv.rb < prev    next >
Encoding:
Ruby Source  |  2010-05-22  |  56.7 KB  |  2,290 lines

  1. require 'socket'
  2. require 'fcntl'
  3. require 'timeout'
  4. require 'thread'
  5.  
  6. begin
  7.   require 'securerandom'
  8. rescue LoadError
  9. end
  10.  
  11. # Resolv is a thread-aware DNS resolver library written in Ruby.  Resolv can
  12. # handle multiple DNS requests concurrently without blocking.  The ruby
  13. # interpreter.
  14. #
  15. # See also resolv-replace.rb to replace the libc resolver with # Resolv.
  16. # Resolv can look up various DNS resources using the DNS module directly.
  17. # Examples:
  18. #   p Resolv.getaddress "www.ruby-lang.org"
  19. #   p Resolv.getname "210.251.121.214"
  20. #   Resolv::DNS.open do |dns|
  21. #     ress = dns.getresources "www.ruby-lang.org", Resolv::DNS::Resource::IN::A
  22. #     p ress.map { |r| r.address }
  23. #     ress = dns.getresources "ruby-lang.org", Resolv::DNS::Resource::IN::MX
  24. #     p ress.map { |r| [r.exchange.to_s, r.preference] }
  25. #   end
  26. # == Bugs
  27. # * NIS is not supported.
  28. # * /etc/nsswitch.conf is not supported.
  29.  
  30. class Resolv
  31.  
  32.   ##
  33.   # Looks up the first IP address for +name+.
  34.   
  35.   def self.getaddress(name)
  36.     DefaultResolver.getaddress(name)
  37.   end
  38.  
  39.   ##
  40.   # Looks up all IP address for +name+.
  41.   
  42.   def self.getaddresses(name)
  43.     DefaultResolver.getaddresses(name)
  44.   end
  45.  
  46.   ##
  47.   # Iterates over all IP addresses for +name+.
  48.  
  49.   def self.each_address(name, &block)
  50.     DefaultResolver.each_address(name, &block)
  51.   end
  52.  
  53.   ##
  54.   # Looks up the hostname of +address+.
  55.  
  56.   def self.getname(address)
  57.     DefaultResolver.getname(address)
  58.   end
  59.  
  60.   ##
  61.   # Looks up all hostnames for +address+.
  62.  
  63.   def self.getnames(address)
  64.     DefaultResolver.getnames(address)
  65.   end
  66.  
  67.   ##
  68.   # Iterates over all hostnames for +address+.
  69.  
  70.   def self.each_name(address, &proc)
  71.     DefaultResolver.each_name(address, &proc)
  72.   end
  73.  
  74.   ##
  75.   # Creates a new Resolv using +resolvers+.
  76.  
  77.   def initialize(resolvers=[Hosts.new, DNS.new])
  78.     @resolvers = resolvers
  79.   end
  80.  
  81.   ##
  82.   # Looks up the first IP address for +name+.
  83.   
  84.   def getaddress(name)
  85.     each_address(name) {|address| return address}
  86.     raise ResolvError.new("no address for #{name}")
  87.   end
  88.  
  89.   ##
  90.   # Looks up all IP address for +name+.
  91.   
  92.   def getaddresses(name)
  93.     ret = []
  94.     each_address(name) {|address| ret << address}
  95.     return ret
  96.   end
  97.  
  98.   ##
  99.   # Iterates over all IP addresses for +name+.
  100.  
  101.   def each_address(name)
  102.     if AddressRegex =~ name
  103.       yield name
  104.       return
  105.     end
  106.     yielded = false
  107.     @resolvers.each {|r|
  108.       r.each_address(name) {|address|
  109.         yield address.to_s
  110.         yielded = true
  111.       }
  112.       return if yielded
  113.     }
  114.   end
  115.  
  116.   ##
  117.   # Looks up the hostname of +address+.
  118.  
  119.   def getname(address)
  120.     each_name(address) {|name| return name}
  121.     raise ResolvError.new("no name for #{address}")
  122.   end
  123.  
  124.   ##
  125.   # Looks up all hostnames for +address+.
  126.  
  127.   def getnames(address)
  128.     ret = []
  129.     each_name(address) {|name| ret << name}
  130.     return ret
  131.   end
  132.  
  133.   ##
  134.   # Iterates over all hostnames for +address+.
  135.  
  136.   def each_name(address)
  137.     yielded = false
  138.     @resolvers.each {|r|
  139.       r.each_name(address) {|name|
  140.         yield name.to_s
  141.         yielded = true
  142.       }
  143.       return if yielded
  144.     }
  145.   end
  146.  
  147.   ##
  148.   # Indicates a failure to resolve a name or address.
  149.  
  150.   class ResolvError < StandardError; end
  151.  
  152.   ##
  153.   # Indicates a timeout resolving a name or address.
  154.  
  155.   class ResolvTimeout < TimeoutError; end
  156.  
  157.   ##
  158.   # DNS::Hosts is a hostname resolver that uses the system hosts file.
  159.  
  160.   class Hosts
  161.     if /mswin32|mingw|bccwin/ =~ RUBY_PLATFORM
  162.       require 'win32/resolv'
  163.       DefaultFileName = Win32::Resolv.get_hosts_path
  164.     else
  165.       DefaultFileName = '/etc/hosts'
  166.     end
  167.  
  168.     ##
  169.     # Creates a new DNS::Hosts, using +filename+ for its data source.
  170.  
  171.     def initialize(filename = DefaultFileName)
  172.       @filename = filename
  173.       @mutex = Mutex.new
  174.       @initialized = nil
  175.     end
  176.  
  177.     def lazy_initialize # :nodoc:
  178.       @mutex.synchronize {
  179.         unless @initialized
  180.           @name2addr = {}
  181.           @addr2name = {}
  182.           open(@filename) {|f|
  183.             f.each {|line|
  184.               line.sub!(/#.*/, '')
  185.               addr, hostname, *aliases = line.split(/\s+/)
  186.               next unless addr
  187.               addr.untaint
  188.               hostname.untaint
  189.               @addr2name[addr] = [] unless @addr2name.include? addr
  190.               @addr2name[addr] << hostname
  191.               @addr2name[addr] += aliases
  192.               @name2addr[hostname] = [] unless @name2addr.include? hostname
  193.               @name2addr[hostname] << addr
  194.               aliases.each {|n|
  195.                 n.untaint
  196.                 @name2addr[n] = [] unless @name2addr.include? n
  197.                 @name2addr[n] << addr
  198.               }
  199.             }
  200.           }
  201.           @name2addr.each {|name, arr| arr.reverse!}
  202.           @initialized = true
  203.         end
  204.       }
  205.       self
  206.     end
  207.  
  208.     ##
  209.     # Gets the IP address of +name+ from the hosts file.
  210.  
  211.     def getaddress(name)
  212.       each_address(name) {|address| return address}
  213.       raise ResolvError.new("#{@filename} has no name: #{name}")
  214.     end
  215.  
  216.     ##
  217.     # Gets all IP addresses for +name+ from the hosts file.
  218.  
  219.     def getaddresses(name)
  220.       ret = []
  221.       each_address(name) {|address| ret << address}
  222.       return ret
  223.     end
  224.  
  225.     ##
  226.     # Iterates over all IP addresses for +name+ retrieved from the hosts file.
  227.  
  228.     def each_address(name, &proc)
  229.       lazy_initialize
  230.       if @name2addr.include?(name)
  231.         @name2addr[name].each(&proc)
  232.       end
  233.     end
  234.  
  235.     ##
  236.     # Gets the hostname of +address+ from the hosts file.
  237.  
  238.     def getname(address)
  239.       each_name(address) {|name| return name}
  240.       raise ResolvError.new("#{@filename} has no address: #{address}")
  241.     end
  242.  
  243.     ##
  244.     # Gets all hostnames for +address+ from the hosts file.
  245.  
  246.     def getnames(address)
  247.       ret = []
  248.       each_name(address) {|name| ret << name}
  249.       return ret
  250.     end
  251.  
  252.     ##
  253.     # Iterates over all hostnames for +address+ retrieved from the hosts file.
  254.  
  255.     def each_name(address, &proc)
  256.       lazy_initialize
  257.       if @addr2name.include?(address)
  258.         @addr2name[address].each(&proc)
  259.       end
  260.     end
  261.   end
  262.  
  263.   ##
  264.   # Resolv::DNS is a DNS stub resolver.
  265.   #
  266.   # Information taken from the following places:
  267.   #
  268.   # * STD0013
  269.   # * RFC 1035
  270.   # * ftp://ftp.isi.edu/in-notes/iana/assignments/dns-parameters
  271.   # * etc.
  272.  
  273.   class DNS
  274.  
  275.     ##
  276.     # Default DNS Port
  277.  
  278.     Port = 53
  279.  
  280.     ##
  281.     # Default DNS UDP packet size
  282.  
  283.     UDPSize = 512
  284.  
  285.     ##
  286.     # Group of DNS resolver threads (obsolete)
  287.  
  288.     DNSThreadGroup = ThreadGroup.new
  289.  
  290.     ##
  291.     # Creates a new DNS resolver.  See Resolv::DNS.new for argument details.
  292.     #
  293.     # Yields the created DNS resolver to the block, if given, otherwise
  294.     # returns it.
  295.  
  296.     def self.open(*args)
  297.       dns = new(*args)
  298.       return dns unless block_given?
  299.       begin
  300.         yield dns
  301.       ensure
  302.         dns.close
  303.       end
  304.     end
  305.  
  306.     ##
  307.     # Creates a new DNS resolver.
  308.     #
  309.     # +config_info+ can be:
  310.     # 
  311.     # nil:: Uses /etc/resolv.conf.
  312.     # String:: Path to a file using /etc/resolv.conf's format.
  313.     # Hash:: Must contain :nameserver, :search and :ndots keys.
  314.     #
  315.     # Example:
  316.     #
  317.     #   Resolv::DNS.new(:nameserver => ['210.251.121.21'],
  318.     #                   :search => ['ruby-lang.org'],
  319.     #                   :ndots => 1)
  320.  
  321.     def initialize(config_info=nil)
  322.       @mutex = Mutex.new
  323.       @config = Config.new(config_info)
  324.       @initialized = nil
  325.     end
  326.  
  327.     def lazy_initialize # :nodoc:
  328.       @mutex.synchronize {
  329.         unless @initialized
  330.           @config.lazy_initialize
  331.           @initialized = true
  332.         end
  333.       }
  334.       self
  335.     end
  336.  
  337.     ##
  338.     # Closes the DNS resolver.
  339.  
  340.     def close
  341.       @mutex.synchronize {
  342.         if @initialized
  343.           @initialized = false
  344.         end
  345.       }
  346.     end
  347.  
  348.     ##
  349.     # Gets the IP address of +name+ from the DNS resolver.
  350.     #
  351.     # +name+ can be a Resolv::DNS::Name or a String.  Retrieved address will
  352.     # be a Resolv::IPv4 or Resolv::IPv6
  353.  
  354.     def getaddress(name)
  355.       each_address(name) {|address| return address}
  356.       raise ResolvError.new("DNS result has no information for #{name}")
  357.     end
  358.  
  359.     ##
  360.     # Gets all IP addresses for +name+ from the DNS resolver.
  361.     #
  362.     # +name+ can be a Resolv::DNS::Name or a String.  Retrieved addresses will
  363.     # be a Resolv::IPv4 or Resolv::IPv6
  364.  
  365.     def getaddresses(name)
  366.       ret = []
  367.       each_address(name) {|address| ret << address}
  368.       return ret
  369.     end
  370.  
  371.     ##
  372.     # Iterates over all IP addresses for +name+ retrieved from the DNS
  373.     # resolver.
  374.     #
  375.     # +name+ can be a Resolv::DNS::Name or a String.  Retrieved addresses will
  376.     # be a Resolv::IPv4 or Resolv::IPv6
  377.  
  378.     def each_address(name)
  379.       each_resource(name, Resource::IN::A) {|resource| yield resource.address}
  380.       each_resource(name, Resource::IN::AAAA) {|resource| yield resource.address}
  381.     end
  382.  
  383.     ##
  384.     # Gets the hostname for +address+ from the DNS resolver.
  385.     #
  386.     # +address+ must be a Resolv::IPv4, Resolv::IPv6 or a String.  Retrieved
  387.     # name will be a Resolv::DNS::Name.
  388.  
  389.     def getname(address)
  390.       each_name(address) {|name| return name}
  391.       raise ResolvError.new("DNS result has no information for #{address}")
  392.     end
  393.  
  394.     ##
  395.     # Gets all hostnames for +address+ from the DNS resolver.
  396.     #
  397.     # +address+ must be a Resolv::IPv4, Resolv::IPv6 or a String.  Retrieved
  398.     # names will be Resolv::DNS::Name instances.
  399.  
  400.     def getnames(address)
  401.       ret = []
  402.       each_name(address) {|name| ret << name}
  403.       return ret
  404.     end
  405.  
  406.     ##
  407.     # Iterates over all hostnames for +address+ retrieved from the DNS
  408.     # resolver.
  409.     #
  410.     # +address+ must be a Resolv::IPv4, Resolv::IPv6 or a String.  Retrieved
  411.     # names will be Resolv::DNS::Name instances.
  412.  
  413.     def each_name(address)
  414.       case address
  415.       when Name
  416.         ptr = address
  417.       when IPv4::Regex
  418.         ptr = IPv4.create(address).to_name
  419.       when IPv6::Regex
  420.         ptr = IPv6.create(address).to_name
  421.       else
  422.         raise ResolvError.new("cannot interpret as address: #{address}")
  423.       end
  424.       each_resource(ptr, Resource::IN::PTR) {|resource| yield resource.name}
  425.     end
  426.  
  427.     ##
  428.     # Look up the +typeclass+ DNS resource of +name+.
  429.     #
  430.     # +name+ must be a Resolv::DNS::Name or a String.
  431.     #
  432.     # +typeclass+ should be one of the following:
  433.     #
  434.     # * Resolv::DNS::Resource::IN::A
  435.     # * Resolv::DNS::Resource::IN::AAAA
  436.     # * Resolv::DNS::Resource::IN::ANY
  437.     # * Resolv::DNS::Resource::IN::CNAME
  438.     # * Resolv::DNS::Resource::IN::HINFO
  439.     # * Resolv::DNS::Resource::IN::MINFO
  440.     # * Resolv::DNS::Resource::IN::MX
  441.     # * Resolv::DNS::Resource::IN::NS
  442.     # * Resolv::DNS::Resource::IN::PTR
  443.     # * Resolv::DNS::Resource::IN::SOA
  444.     # * Resolv::DNS::Resource::IN::TXT
  445.     # * Resolv::DNS::Resource::IN::WKS
  446.     #
  447.     # Returned resource is represented as a Resolv::DNS::Resource instance,
  448.     # i.e. Resolv::DNS::Resource::IN::A.
  449.  
  450.     def getresource(name, typeclass)
  451.       each_resource(name, typeclass) {|resource| return resource}
  452.       raise ResolvError.new("DNS result has no information for #{name}")
  453.     end
  454.  
  455.     ##
  456.     # Looks up all +typeclass+ DNS resources for +name+.  See #getresource for
  457.     # argument details.
  458.   
  459.     def getresources(name, typeclass)
  460.       ret = []
  461.       each_resource(name, typeclass) {|resource| ret << resource}
  462.       return ret
  463.     end
  464.  
  465.     ##
  466.     # Iterates over all +typeclass+ DNS resources for +name+.  See
  467.     # #getresource for argument details.
  468.   
  469.     def each_resource(name, typeclass, &proc)
  470.       lazy_initialize
  471.       requester = make_requester
  472.       senders = {}
  473.       begin
  474.         @config.resolv(name) {|candidate, tout, nameserver|
  475.           msg = Message.new
  476.           msg.rd = 1
  477.           msg.add_question(candidate, typeclass)
  478.           unless sender = senders[[candidate, nameserver]]
  479.             sender = senders[[candidate, nameserver]] =
  480.               requester.sender(msg, candidate, nameserver)
  481.           end
  482.           reply, reply_name = requester.request(sender, tout)
  483.           case reply.rcode
  484.           when RCode::NoError
  485.             extract_resources(reply, reply_name, typeclass, &proc)
  486.             return
  487.           when RCode::NXDomain
  488.             raise Config::NXDomain.new(reply_name.to_s)
  489.           else
  490.             raise Config::OtherResolvError.new(reply_name.to_s)
  491.           end
  492.         }
  493.       ensure
  494.         requester.close
  495.       end
  496.     end
  497.  
  498.     def make_requester # :nodoc:
  499.       nameserver_port = @config.nameserver_port
  500.       if nameserver_port.length == 1
  501.         Requester::ConnectedUDP.new(*nameserver_port[0])
  502.       else
  503.         Requester::UnconnectedUDP.new(*nameserver_port)
  504.       end
  505.     end
  506.  
  507.     def extract_resources(msg, name, typeclass) # :nodoc:
  508.       if typeclass < Resource::ANY
  509.         n0 = Name.create(name)
  510.         msg.each_answer {|n, ttl, data|
  511.           yield data if n0 == n
  512.         }
  513.       end
  514.       yielded = false
  515.       n0 = Name.create(name)
  516.       msg.each_answer {|n, ttl, data|
  517.         if n0 == n
  518.           case data
  519.           when typeclass
  520.             yield data
  521.             yielded = true
  522.           when Resource::CNAME
  523.             n0 = data.name
  524.           end
  525.         end
  526.       }
  527.       return if yielded
  528.       msg.each_answer {|n, ttl, data|
  529.         if n0 == n
  530.           case data
  531.           when typeclass
  532.             yield data
  533.           end
  534.         end
  535.       }
  536.     end
  537.  
  538.     if defined? SecureRandom
  539.       def self.random(arg) # :nodoc:
  540.         begin
  541.           SecureRandom.random_number(arg)
  542.         rescue NotImplementedError
  543.           rand(arg)
  544.         end
  545.       end
  546.     else
  547.       def self.random(arg) # :nodoc:
  548.         rand(arg)
  549.       end
  550.     end
  551.  
  552.  
  553.     def self.rangerand(range) # :nodoc:
  554.       base = range.begin
  555.       len = range.end - range.begin
  556.       if !range.exclude_end?
  557.         len += 1
  558.       end
  559.       base + random(len)
  560.     end
  561.  
  562.     RequestID = {}
  563.     RequestIDMutex = Mutex.new
  564.  
  565.     def self.allocate_request_id(host, port) # :nodoc:
  566.       id = nil
  567.       RequestIDMutex.synchronize {
  568.         h = (RequestID[[host, port]] ||= {})
  569.         begin
  570.           id = rangerand(0x0000..0xffff)
  571.         end while h[id] 
  572.         h[id] = true
  573.       }
  574.       id
  575.     end
  576.  
  577.     def self.free_request_id(host, port, id) # :nodoc:
  578.       RequestIDMutex.synchronize {
  579.         key = [host, port]
  580.         if h = RequestID[key]
  581.           h.delete id
  582.           if h.empty?
  583.             RequestID.delete key
  584.           end
  585.         end
  586.       }
  587.     end
  588.  
  589.     def self.bind_random_port(udpsock, bind_host="0.0.0.0") # :nodoc:
  590.       begin
  591.         port = rangerand(1024..65535)
  592.         udpsock.bind(bind_host, port)
  593.       rescue Errno::EADDRINUSE
  594.         retry
  595.       end
  596.     end
  597.  
  598.     class Requester # :nodoc:
  599.       def initialize
  600.         @senders = {}
  601.         @socks = nil
  602.       end
  603.  
  604.       def request(sender, tout)
  605.         timelimit = Time.now + tout
  606.         sender.send
  607.         while true
  608.           now = Time.now
  609.           timeout = timelimit - now
  610.           if timeout <= 0
  611.             raise ResolvTimeout
  612.           end
  613.           select_result = IO.select(@socks, nil, nil, timeout)
  614.           if !select_result
  615.             raise ResolvTimeout
  616.           end
  617.           reply, from = recv_reply(select_result[0])
  618.           begin
  619.             msg = Message.decode(reply)
  620.           rescue DecodeError
  621.             next # broken DNS message ignored
  622.           end
  623.           if s = @senders[[from,msg.id]]
  624.             break
  625.           else
  626.             # unexpected DNS message ignored
  627.           end
  628.         end
  629.         return msg, s.data
  630.       end
  631.  
  632.       def close
  633.         socks = @socks
  634.         @socks = nil
  635.         if socks
  636.           socks.each {|sock| sock.close }
  637.         end
  638.       end
  639.  
  640.       class Sender # :nodoc:
  641.         def initialize(msg, data, sock)
  642.           @msg = msg
  643.           @data = data
  644.           @sock = sock
  645.         end
  646.       end
  647.  
  648.       class UnconnectedUDP < Requester # :nodoc:
  649.         def initialize(*nameserver_port)
  650.           super()
  651.           @nameserver_port = nameserver_port
  652.           @socks_hash = {}
  653.           @socks = []
  654.           nameserver_port.each {|host, port|
  655.             if host.index(':')
  656.               bind_host = "::"
  657.               af = Socket::AF_INET6
  658.             else
  659.               bind_host = "0.0.0.0"
  660.               af = Socket::AF_INET
  661.             end
  662.             next if @socks_hash[bind_host]
  663.             sock = UDPSocket.new(af)
  664.             sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD
  665.             DNS.bind_random_port(sock, bind_host)
  666.             @socks << sock
  667.             @socks_hash[bind_host] = sock
  668.           }
  669.         end
  670.  
  671.         def recv_reply(readable_socks)
  672.           reply, from = readable_socks[0].recvfrom(UDPSize)
  673.           return reply, [from[3],from[1]]
  674.         end
  675.  
  676.         def sender(msg, data, host, port=Port)
  677.           service = [host, port]
  678.           id = DNS.allocate_request_id(host, port)
  679.           request = msg.encode
  680.           request[0,2] = [id].pack('n')
  681.           sock = @socks_hash[host.index(':') ? "::" : "0.0.0.0"]
  682.           return @senders[[service, id]] =
  683.             Sender.new(request, data, sock, host, port)
  684.         end
  685.  
  686.         def close
  687.           super
  688.           @senders.each_key {|service, id|
  689.             DNS.free_request_id(service[0], service[1], id)
  690.           }
  691.         end
  692.  
  693.         class Sender < Requester::Sender # :nodoc:
  694.           def initialize(msg, data, sock, host, port)
  695.             super(msg, data, sock)
  696.             @host = host
  697.             @port = port
  698.           end
  699.           attr_reader :data
  700.  
  701.           def send
  702.             @sock.send(@msg, 0, @host, @port)
  703.           end
  704.         end
  705.       end
  706.  
  707.       class ConnectedUDP < Requester # :nodoc:
  708.         def initialize(host, port=Port)
  709.           super()
  710.           @host = host
  711.           @port = port
  712.           is_ipv6 = host.index(':')
  713.           sock = UDPSocket.new(is_ipv6 ? Socket::AF_INET6 : Socket::AF_INET)
  714.           @socks = [sock]
  715.           sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD
  716.           DNS.bind_random_port(sock, is_ipv6 ? "::" : "0.0.0.0")
  717.           sock.connect(host, port)
  718.         end
  719.  
  720.         def recv_reply(readable_socks)
  721.           reply = readable_socks[0].recv(UDPSize)
  722.           return reply, nil
  723.         end
  724.  
  725.         def sender(msg, data, host=@host, port=@port)
  726.           unless host == @host && port == @port
  727.             raise RequestError.new("host/port don't match: #{host}:#{port}")
  728.           end
  729.           id = DNS.allocate_request_id(@host, @port)
  730.           request = msg.encode
  731.           request[0,2] = [id].pack('n')
  732.           return @senders[[nil,id]] = Sender.new(request, data, @socks[0])
  733.         end
  734.  
  735.         def close
  736.           super
  737.           @senders.each_key {|from, id|
  738.             DNS.free_request_id(@host, @port, id)
  739.           }
  740.         end
  741.  
  742.         class Sender < Requester::Sender # :nodoc:
  743.           def send
  744.             @sock.send(@msg, 0)
  745.           end
  746.           attr_reader :data
  747.         end
  748.       end
  749.  
  750.       class TCP < Requester # :nodoc:
  751.         def initialize(host, port=Port)
  752.           super()
  753.           @host = host
  754.           @port = port
  755.           sock = TCPSocket.new(@host, @port)
  756.           @socks = [sock]
  757.           sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::F_SETFD
  758.           @senders = {}
  759.         end
  760.  
  761.         def recv_reply(readable_socks)
  762.           len = readable_socks[0].read(2).unpack('n')[0]
  763.           reply = @socks[0].read(len)
  764.           return reply, nil
  765.         end
  766.  
  767.         def sender(msg, data, host=@host, port=@port)
  768.           unless host == @host && port == @port
  769.             raise RequestError.new("host/port don't match: #{host}:#{port}")
  770.           end
  771.           id = DNS.allocate_request_id(@host, @port)
  772.           request = msg.encode
  773.           request[0,2] = [request.length, id].pack('nn')
  774.           return @senders[[nil,id]] = Sender.new(request, data, @socks[0])
  775.         end
  776.  
  777.         class Sender < Requester::Sender # :nodoc:
  778.           def send
  779.             @sock.print(@msg)
  780.             @sock.flush
  781.           end
  782.           attr_reader :data
  783.         end
  784.  
  785.         def close
  786.           super
  787.           @senders.each_key {|from,id|
  788.             DNS.free_request_id(@host, @port, id)
  789.           }
  790.         end
  791.       end
  792.  
  793.       ##
  794.       # Indicates a problem with the DNS request.
  795.  
  796.       class RequestError < StandardError
  797.       end
  798.     end
  799.  
  800.     class Config # :nodoc:
  801.       def initialize(config_info=nil)
  802.         @mutex = Mutex.new
  803.         @config_info = config_info
  804.         @initialized = nil
  805.       end
  806.  
  807.       def Config.parse_resolv_conf(filename)
  808.         nameserver = []
  809.         search = nil
  810.         ndots = 1
  811.         open(filename) {|f|
  812.           f.each {|line|
  813.             line.sub!(/[#;].*/, '')
  814.             keyword, *args = line.split(/\s+/)
  815.             args.each { |arg|
  816.               arg.untaint
  817.             }
  818.             next unless keyword
  819.             case keyword
  820.             when 'nameserver'
  821.               nameserver += args
  822.             when 'domain'
  823.               next if args.empty?
  824.               search = [args[0]]
  825.             when 'search'
  826.               next if args.empty?
  827.               search = args
  828.             when 'options'
  829.               args.each {|arg|
  830.                 case arg
  831.                 when /\Andots:(\d+)\z/
  832.                   ndots = $1.to_i
  833.                 end
  834.               }
  835.             end
  836.           }
  837.         }
  838.         return { :nameserver => nameserver, :search => search, :ndots => ndots }
  839.       end
  840.  
  841.       def Config.default_config_hash(filename="/etc/resolv.conf")
  842.         if File.exist? filename
  843.           config_hash = Config.parse_resolv_conf(filename)
  844.         else
  845.           if /mswin32|cygwin|mingw|bccwin/ =~ RUBY_PLATFORM
  846.             require 'win32/resolv'
  847.             search, nameserver = Win32::Resolv.get_resolv_info
  848.             config_hash = {}
  849.             config_hash[:nameserver] = nameserver if nameserver
  850.             config_hash[:search] = [search].flatten if search
  851.           end
  852.         end
  853.         config_hash
  854.       end
  855.  
  856.       def lazy_initialize
  857.         @mutex.synchronize {
  858.           unless @initialized
  859.             @nameserver = []
  860.             @search = nil
  861.             @ndots = 1
  862.             case @config_info
  863.             when nil
  864.               config_hash = Config.default_config_hash
  865.             when String
  866.               config_hash = Config.parse_resolv_conf(@config_info)
  867.             when Hash
  868.               config_hash = @config_info.dup
  869.               if String === config_hash[:nameserver]
  870.                 config_hash[:nameserver] = [config_hash[:nameserver]]
  871.               end
  872.               if String === config_hash[:search]
  873.                 config_hash[:search] = [config_hash[:search]]
  874.               end
  875.             else
  876.               raise ArgumentError.new("invalid resolv configuration: #{@config_info.inspect}")
  877.             end
  878.             @nameserver = config_hash[:nameserver] if config_hash.include? :nameserver
  879.             @search = config_hash[:search] if config_hash.include? :search
  880.             @ndots = config_hash[:ndots] if config_hash.include? :ndots
  881.  
  882.             @nameserver = ['0.0.0.0'] if @nameserver.empty?
  883.             if @search
  884.               @search = @search.map {|arg| Label.split(arg) }
  885.             else
  886.               hostname = Socket.gethostname
  887.               if /\./ =~ hostname
  888.                 @search = [Label.split($')]
  889.               else
  890.                 @search = [[]]
  891.               end
  892.             end
  893.  
  894.             if !@nameserver.kind_of?(Array) ||
  895.                !@nameserver.all? {|ns| String === ns }
  896.               raise ArgumentError.new("invalid nameserver config: #{@nameserver.inspect}")
  897.             end
  898.  
  899.             if !@search.kind_of?(Array) ||
  900.                !@search.all? {|ls| ls.all? {|l| Label::Str === l } }
  901.               raise ArgumentError.new("invalid search config: #{@search.inspect}")
  902.             end
  903.  
  904.             if !@ndots.kind_of?(Integer)
  905.               raise ArgumentError.new("invalid ndots config: #{@ndots.inspect}")
  906.             end
  907.  
  908.             @initialized = true
  909.           end
  910.         }
  911.         self
  912.       end
  913.  
  914.       def single?
  915.         lazy_initialize
  916.         if @nameserver.length == 1
  917.           return @nameserver[0]
  918.         else
  919.           return nil
  920.         end
  921.       end
  922.  
  923.       def nameserver_port
  924.         lazy_initialize
  925.         @nameserver_port ||= @nameserver.map {|i| [i, Port] }
  926.         @nameserver_port
  927.       end
  928.  
  929.       def generate_candidates(name)
  930.         candidates = nil
  931.         name = Name.create(name)
  932.         if name.absolute?
  933.           candidates = [name]
  934.         else
  935.           if @ndots <= name.length - 1
  936.             candidates = [Name.new(name.to_a)]
  937.           else
  938.             candidates = []
  939.           end
  940.           candidates.concat(@search.map {|domain| Name.new(name.to_a + domain)})
  941.         end
  942.         return candidates
  943.       end
  944.  
  945.       InitialTimeout = 5
  946.  
  947.       def generate_timeouts
  948.         ts = [InitialTimeout]
  949.         ts << ts[-1] * 2 / @nameserver.length
  950.         ts << ts[-1] * 2
  951.         ts << ts[-1] * 2
  952.         return ts
  953.       end
  954.  
  955.       def resolv(name)
  956.         candidates = generate_candidates(name)
  957.         timeouts = generate_timeouts
  958.         begin
  959.           candidates.each {|candidate|
  960.             begin
  961.               timeouts.each {|tout|
  962.                 @nameserver.each {|nameserver|
  963.                   begin
  964.                     yield candidate, tout, nameserver
  965.                   rescue ResolvTimeout
  966.                   end
  967.                 }
  968.               }
  969.               raise ResolvError.new("DNS resolv timeout: #{name}")
  970.             rescue NXDomain
  971.             end
  972.           }
  973.         rescue ResolvError
  974.         end
  975.       end
  976.  
  977.       ##
  978.       # Indicates no such domain was found.
  979.  
  980.       class NXDomain < ResolvError
  981.       end
  982.  
  983.       ##
  984.       # Indicates some other unhandled resolver error was encountered.
  985.  
  986.       class OtherResolvError < ResolvError
  987.       end
  988.     end
  989.  
  990.     module OpCode # :nodoc:
  991.       Query = 0
  992.       IQuery = 1
  993.       Status = 2
  994.       Notify = 4
  995.       Update = 5
  996.     end
  997.  
  998.     module RCode # :nodoc:
  999.       NoError = 0
  1000.       FormErr = 1
  1001.       ServFail = 2
  1002.       NXDomain = 3
  1003.       NotImp = 4
  1004.       Refused = 5
  1005.       YXDomain = 6
  1006.       YXRRSet = 7
  1007.       NXRRSet = 8
  1008.       NotAuth = 9
  1009.       NotZone = 10
  1010.       BADVERS = 16
  1011.       BADSIG = 16
  1012.       BADKEY = 17
  1013.       BADTIME = 18
  1014.       BADMODE = 19
  1015.       BADNAME = 20
  1016.       BADALG = 21
  1017.     end
  1018.  
  1019.     ##
  1020.     # Indicates that the DNS response was unable to be decoded.
  1021.  
  1022.     class DecodeError < StandardError
  1023.     end
  1024.  
  1025.     ##
  1026.     # Indicates that the DNS request was unable to be encoded.
  1027.  
  1028.     class EncodeError < StandardError
  1029.     end
  1030.  
  1031.     module Label # :nodoc:
  1032.       def self.split(arg)
  1033.         labels = []
  1034.         arg.scan(/[^\.]+/) {labels << Str.new($&)}
  1035.         return labels
  1036.       end
  1037.  
  1038.       class Str # :nodoc:
  1039.         def initialize(string)
  1040.           @string = string
  1041.           @downcase = string.downcase
  1042.         end
  1043.         attr_reader :string, :downcase
  1044.  
  1045.         def to_s
  1046.           return @string
  1047.         end
  1048.  
  1049.         def inspect
  1050.           return "#<#{self.class} #{self.to_s}>"
  1051.         end
  1052.  
  1053.         def ==(other)
  1054.           return @downcase == other.downcase
  1055.         end
  1056.  
  1057.         def eql?(other)
  1058.           return self == other
  1059.         end
  1060.  
  1061.         def hash
  1062.           return @downcase.hash
  1063.         end
  1064.       end
  1065.     end
  1066.  
  1067.     ##
  1068.     # A representation of a DNS name.
  1069.  
  1070.     class Name
  1071.       
  1072.       ##
  1073.       # Creates a new DNS name from +arg+.  +arg+ can be:
  1074.       #
  1075.       # Name:: returns +arg+.
  1076.       # String:: Creates a new Name.
  1077.  
  1078.       def self.create(arg)
  1079.         case arg
  1080.         when Name
  1081.           return arg
  1082.         when String
  1083.           return Name.new(Label.split(arg), /\.\z/ =~ arg ? true : false)
  1084.         else
  1085.           raise ArgumentError.new("cannot interpret as DNS name: #{arg.inspect}")
  1086.         end
  1087.       end
  1088.  
  1089.       def initialize(labels, absolute=true) # :nodoc:
  1090.         @labels = labels
  1091.         @absolute = absolute
  1092.       end
  1093.  
  1094.       def inspect # :nodoc:
  1095.         "#<#{self.class}: #{self.to_s}#{@absolute ? '.' : ''}>"
  1096.       end
  1097.  
  1098.       ##
  1099.       # True if this name is absolute.
  1100.  
  1101.       def absolute?
  1102.         return @absolute
  1103.       end
  1104.  
  1105.       def ==(other) # :nodoc:
  1106.         return false unless Name === other
  1107.         return @labels.join == other.to_a.join && @absolute == other.absolute?
  1108.       end
  1109.  
  1110.       alias eql? == # :nodoc:
  1111.  
  1112.       ##
  1113.       # Returns true if +other+ is a subdomain.
  1114.       #
  1115.       # Example:
  1116.       #
  1117.       #   domain = Resolv::DNS::Name.create("y.z")
  1118.       #   p Resolv::DNS::Name.create("w.x.y.z").subdomain_of?(domain) #=> true
  1119.       #   p Resolv::DNS::Name.create("x.y.z").subdomain_of?(domain) #=> true
  1120.       #   p Resolv::DNS::Name.create("y.z").subdomain_of?(domain) #=> false
  1121.       #   p Resolv::DNS::Name.create("z").subdomain_of?(domain) #=> false
  1122.       #   p Resolv::DNS::Name.create("x.y.z.").subdomain_of?(domain) #=> false
  1123.       #   p Resolv::DNS::Name.create("w.z").subdomain_of?(domain) #=> false
  1124.       #
  1125.  
  1126.       def subdomain_of?(other)
  1127.         raise ArgumentError, "not a domain name: #{other.inspect}" unless Name === other
  1128.         return false if @absolute != other.absolute?
  1129.         other_len = other.length
  1130.         return false if @labels.length <= other_len
  1131.         return @labels[-other_len, other_len] == other.to_a
  1132.       end
  1133.  
  1134.       def hash # :nodoc:
  1135.         return @labels.hash ^ @absolute.hash
  1136.       end
  1137.  
  1138.       def to_a # :nodoc:
  1139.         return @labels
  1140.       end
  1141.  
  1142.       def length # :nodoc:
  1143.         return @labels.length
  1144.       end
  1145.  
  1146.       def [](i) # :nodoc:
  1147.         return @labels[i]
  1148.       end
  1149.  
  1150.       ##
  1151.       # returns the domain name as a string.
  1152.       #
  1153.       # The domain name doesn't have a trailing dot even if the name object is
  1154.       # absolute.
  1155.       #
  1156.       # Example:
  1157.       #
  1158.       #   p Resolv::DNS::Name.create("x.y.z.").to_s #=> "x.y.z"
  1159.       #   p Resolv::DNS::Name.create("x.y.z").to_s #=> "x.y.z"
  1160.  
  1161.       def to_s
  1162.         return @labels.join('.')
  1163.       end
  1164.     end
  1165.  
  1166.     class Message # :nodoc:
  1167.       @@identifier = -1
  1168.  
  1169.       def initialize(id = (@@identifier += 1) & 0xffff)
  1170.         @id = id
  1171.         @qr = 0
  1172.         @opcode = 0
  1173.         @aa = 0
  1174.         @tc = 0
  1175.         @rd = 0 # recursion desired
  1176.         @ra = 0 # recursion available
  1177.         @rcode = 0
  1178.         @question = []
  1179.         @answer = []
  1180.         @authority = []
  1181.         @additional = []
  1182.       end
  1183.  
  1184.       attr_accessor :id, :qr, :opcode, :aa, :tc, :rd, :ra, :rcode
  1185.       attr_reader :question, :answer, :authority, :additional
  1186.  
  1187.       def ==(other)
  1188.         return @id == other.id &&
  1189.                @qr == other.qr &&
  1190.                @opcode == other.opcode &&
  1191.                @aa == other.aa &&
  1192.                @tc == other.tc &&
  1193.                @rd == other.rd &&
  1194.                @ra == other.ra &&
  1195.                @rcode == other.rcode &&
  1196.                @question == other.question &&
  1197.                @answer == other.answer &&
  1198.                @authority == other.authority &&
  1199.                @additional == other.additional
  1200.       end
  1201.  
  1202.       def add_question(name, typeclass)
  1203.         @question << [Name.create(name), typeclass]
  1204.       end
  1205.  
  1206.       def each_question
  1207.         @question.each {|name, typeclass|
  1208.           yield name, typeclass
  1209.         }
  1210.       end
  1211.  
  1212.       def add_answer(name, ttl, data)
  1213.         @answer << [Name.create(name), ttl, data]
  1214.       end
  1215.  
  1216.       def each_answer
  1217.         @answer.each {|name, ttl, data|
  1218.           yield name, ttl, data
  1219.         }
  1220.       end
  1221.  
  1222.       def add_authority(name, ttl, data)
  1223.         @authority << [Name.create(name), ttl, data]
  1224.       end
  1225.  
  1226.       def each_authority
  1227.         @authority.each {|name, ttl, data|
  1228.           yield name, ttl, data
  1229.         }
  1230.       end
  1231.  
  1232.       def add_additional(name, ttl, data)
  1233.         @additional << [Name.create(name), ttl, data]
  1234.       end
  1235.  
  1236.       def each_additional
  1237.         @additional.each {|name, ttl, data|
  1238.           yield name, ttl, data
  1239.         }
  1240.       end
  1241.  
  1242.       def each_resource
  1243.         each_answer {|name, ttl, data| yield name, ttl, data}
  1244.         each_authority {|name, ttl, data| yield name, ttl, data}
  1245.         each_additional {|name, ttl, data| yield name, ttl, data}
  1246.       end
  1247.  
  1248.       def encode
  1249.         return MessageEncoder.new {|msg|
  1250.           msg.put_pack('nnnnnn',
  1251.             @id,
  1252.             (@qr & 1) << 15 |
  1253.             (@opcode & 15) << 11 |
  1254.             (@aa & 1) << 10 |
  1255.             (@tc & 1) << 9 |
  1256.             (@rd & 1) << 8 |
  1257.             (@ra & 1) << 7 |
  1258.             (@rcode & 15),
  1259.             @question.length,
  1260.             @answer.length,
  1261.             @authority.length,
  1262.             @additional.length)
  1263.           @question.each {|q|
  1264.             name, typeclass = q
  1265.             msg.put_name(name)
  1266.             msg.put_pack('nn', typeclass::TypeValue, typeclass::ClassValue)
  1267.           }
  1268.           [@answer, @authority, @additional].each {|rr|
  1269.             rr.each {|r|
  1270.               name, ttl, data = r
  1271.               msg.put_name(name)
  1272.               msg.put_pack('nnN', data.class::TypeValue, data.class::ClassValue, ttl)
  1273.               msg.put_length16 {data.encode_rdata(msg)}
  1274.             }
  1275.           }
  1276.         }.to_s
  1277.       end
  1278.  
  1279.       class MessageEncoder # :nodoc:
  1280.         def initialize
  1281.           @data = ''
  1282.           @names = {}
  1283.           yield self
  1284.         end
  1285.  
  1286.         def to_s
  1287.           return @data
  1288.         end
  1289.  
  1290.         def put_bytes(d)
  1291.           @data << d
  1292.         end
  1293.  
  1294.         def put_pack(template, *d)
  1295.           @data << d.pack(template)
  1296.         end
  1297.  
  1298.         def put_length16
  1299.           length_index = @data.length
  1300.           @data << "\0\0"
  1301.           data_start = @data.length
  1302.           yield
  1303.           data_end = @data.length
  1304.           @data[length_index, 2] = [data_end - data_start].pack("n")
  1305.         end
  1306.  
  1307.         def put_string(d)
  1308.           self.put_pack("C", d.length)
  1309.           @data << d
  1310.         end
  1311.  
  1312.         def put_string_list(ds)
  1313.           ds.each {|d|
  1314.             self.put_string(d)
  1315.           }
  1316.         end
  1317.  
  1318.         def put_name(d)
  1319.           put_labels(d.to_a)
  1320.         end
  1321.  
  1322.         def put_labels(d)
  1323.           d.each_index {|i|
  1324.             domain = d[i..-1]
  1325.             if idx = @names[domain]
  1326.               self.put_pack("n", 0xc000 | idx)
  1327.               return
  1328.             else
  1329.               @names[domain] = @data.length
  1330.               self.put_label(d[i])
  1331.             end
  1332.           }
  1333.           @data << "\0"
  1334.         end
  1335.  
  1336.         def put_label(d)
  1337.           self.put_string(d.to_s)
  1338.         end
  1339.       end
  1340.  
  1341.       def Message.decode(m)
  1342.         o = Message.new(0)
  1343.         MessageDecoder.new(m) {|msg|
  1344.           id, flag, qdcount, ancount, nscount, arcount =
  1345.             msg.get_unpack('nnnnnn')
  1346.           o.id = id
  1347.           o.qr = (flag >> 15) & 1
  1348.           o.opcode = (flag >> 11) & 15
  1349.           o.aa = (flag >> 10) & 1
  1350.           o.tc = (flag >> 9) & 1
  1351.           o.rd = (flag >> 8) & 1
  1352.           o.ra = (flag >> 7) & 1
  1353.           o.rcode = flag & 15
  1354.           (1..qdcount).each {
  1355.             name, typeclass = msg.get_question
  1356.             o.add_question(name, typeclass)
  1357.           }
  1358.           (1..ancount).each {
  1359.             name, ttl, data = msg.get_rr
  1360.             o.add_answer(name, ttl, data)
  1361.           }
  1362.           (1..nscount).each {
  1363.             name, ttl, data = msg.get_rr
  1364.             o.add_authority(name, ttl, data)
  1365.           }
  1366.           (1..arcount).each {
  1367.             name, ttl, data = msg.get_rr
  1368.             o.add_additional(name, ttl, data)
  1369.           }
  1370.         }
  1371.         return o
  1372.       end
  1373.  
  1374.       class MessageDecoder # :nodoc:
  1375.         def initialize(data)
  1376.           @data = data
  1377.           @index = 0
  1378.           @limit = data.length
  1379.           yield self
  1380.         end
  1381.  
  1382.         def get_length16
  1383.           len, = self.get_unpack('n')
  1384.           save_limit = @limit
  1385.           @limit = @index + len
  1386.           d = yield(len)
  1387.           if @index < @limit
  1388.             raise DecodeError.new("junk exists")
  1389.           elsif @limit < @index
  1390.             raise DecodeError.new("limit exceeded")
  1391.           end
  1392.           @limit = save_limit
  1393.           return d
  1394.         end
  1395.  
  1396.         def get_bytes(len = @limit - @index)
  1397.           d = @data[@index, len]
  1398.           @index += len
  1399.           return d
  1400.         end
  1401.  
  1402.         def get_unpack(template)
  1403.           len = 0
  1404.           template.each_byte {|byte|
  1405.             case byte
  1406.             when ?c, ?C
  1407.               len += 1
  1408.             when ?n
  1409.               len += 2
  1410.             when ?N
  1411.               len += 4
  1412.             else
  1413.               raise StandardError.new("unsupported template: '#{byte.chr}' in '#{template}'")
  1414.             end
  1415.           }
  1416.           raise DecodeError.new("limit exceeded") if @limit < @index + len
  1417.           arr = @data.unpack("@#{@index}#{template}")
  1418.           @index += len
  1419.           return arr
  1420.         end
  1421.  
  1422.         def get_string
  1423.           len = @data[@index]
  1424.           raise DecodeError.new("limit exceeded") if @limit < @index + 1 + len
  1425.           d = @data[@index + 1, len]
  1426.           @index += 1 + len
  1427.           return d
  1428.         end
  1429.  
  1430.         def get_string_list
  1431.           strings = []
  1432.           while @index < @limit
  1433.             strings << self.get_string
  1434.           end
  1435.           strings
  1436.         end
  1437.  
  1438.         def get_name
  1439.           return Name.new(self.get_labels)
  1440.         end
  1441.  
  1442.         def get_labels(limit=nil)
  1443.           limit = @index if !limit || @index < limit
  1444.           d = []
  1445.           while true
  1446.             case @data[@index]
  1447.             when 0
  1448.               @index += 1
  1449.               return d
  1450.             when 192..255
  1451.               idx = self.get_unpack('n')[0] & 0x3fff
  1452.               if limit <= idx
  1453.                 raise DecodeError.new("non-backward name pointer")
  1454.               end
  1455.               save_index = @index
  1456.               @index = idx
  1457.               d += self.get_labels(limit)
  1458.               @index = save_index
  1459.               return d
  1460.             else
  1461.               d << self.get_label
  1462.             end
  1463.           end
  1464.           return d
  1465.         end
  1466.  
  1467.         def get_label
  1468.           return Label::Str.new(self.get_string)
  1469.         end
  1470.  
  1471.         def get_question
  1472.           name = self.get_name
  1473.           type, klass = self.get_unpack("nn")
  1474.           return name, Resource.get_class(type, klass)
  1475.         end
  1476.  
  1477.         def get_rr
  1478.           name = self.get_name
  1479.           type, klass, ttl = self.get_unpack('nnN')
  1480.           typeclass = Resource.get_class(type, klass)
  1481.           return name, ttl, self.get_length16 {typeclass.decode_rdata(self)}
  1482.         end
  1483.       end
  1484.     end
  1485.  
  1486.     ##
  1487.     # A DNS query abstract class.
  1488.  
  1489.     class Query
  1490.       def encode_rdata(msg) # :nodoc:
  1491.         raise EncodeError.new("#{self.class} is query.") 
  1492.       end
  1493.  
  1494.       def self.decode_rdata(msg) # :nodoc:
  1495.         raise DecodeError.new("#{self.class} is query.") 
  1496.       end
  1497.     end
  1498.  
  1499.     ##
  1500.     # A DNS resource abstract class.
  1501.  
  1502.     class Resource < Query
  1503.  
  1504.       ##
  1505.       # Remaining Time To Live for this Resource.
  1506.  
  1507.       attr_reader :ttl
  1508.  
  1509.       ClassHash = {} # :nodoc:
  1510.  
  1511.       def encode_rdata(msg) # :nodoc:
  1512.         raise NotImplementedError.new
  1513.       end
  1514.  
  1515.       def self.decode_rdata(msg) # :nodoc:
  1516.         raise NotImplementedError.new
  1517.       end
  1518.  
  1519.       def ==(other) # :nodoc:
  1520.         return self.class == other.class &&
  1521.           self.instance_variables == other.instance_variables &&
  1522.           self.instance_variables.collect {|name| self.instance_eval name} ==
  1523.             other.instance_variables.collect {|name| other.instance_eval name}
  1524.       end
  1525.  
  1526.       def eql?(other) # :nodoc:
  1527.         return self == other
  1528.       end
  1529.  
  1530.       def hash # :nodoc:
  1531.         h = 0
  1532.         self.instance_variables.each {|name|
  1533.           h ^= self.instance_eval("#{name}.hash")
  1534.         }
  1535.         return h
  1536.       end
  1537.  
  1538.       def self.get_class(type_value, class_value) # :nodoc:
  1539.         return ClassHash[[type_value, class_value]] ||
  1540.                Generic.create(type_value, class_value)
  1541.       end
  1542.  
  1543.       ##
  1544.       # A generic resource abstract class.
  1545.  
  1546.       class Generic < Resource
  1547.  
  1548.         ##
  1549.         # Creates a new generic resource.
  1550.  
  1551.         def initialize(data)
  1552.           @data = data
  1553.         end
  1554.  
  1555.         ##
  1556.         # Data for this generic resource.
  1557.  
  1558.         attr_reader :data
  1559.  
  1560.         def encode_rdata(msg) # :nodoc:
  1561.           msg.put_bytes(data)
  1562.         end
  1563.  
  1564.         def self.decode_rdata(msg) # :nodoc:
  1565.           return self.new(msg.get_bytes)
  1566.         end
  1567.  
  1568.         def self.create(type_value, class_value) # :nodoc:
  1569.           c = Class.new(Generic)
  1570.           c.const_set(:TypeValue, type_value)
  1571.           c.const_set(:ClassValue, class_value)
  1572.           Generic.const_set("Type#{type_value}_Class#{class_value}", c)
  1573.           ClassHash[[type_value, class_value]] = c
  1574.           return c
  1575.         end
  1576.       end
  1577.  
  1578.       ##
  1579.       # Domain Name resource abstract class.
  1580.  
  1581.       class DomainName < Resource
  1582.  
  1583.         ##
  1584.         # Creates a new DomainName from +name+.
  1585.  
  1586.         def initialize(name)
  1587.           @name = name
  1588.         end
  1589.  
  1590.         ##
  1591.         # The name of this DomainName.
  1592.  
  1593.         attr_reader :name
  1594.  
  1595.         def encode_rdata(msg) # :nodoc:
  1596.           msg.put_name(@name)
  1597.         end
  1598.  
  1599.         def self.decode_rdata(msg) # :nodoc:
  1600.           return self.new(msg.get_name)
  1601.         end
  1602.       end
  1603.  
  1604.       # Standard (class generic) RRs
  1605.  
  1606.       ClassValue = nil # :nodoc:
  1607.  
  1608.       ##
  1609.       # An authoritative name server.
  1610.  
  1611.       class NS < DomainName
  1612.         TypeValue = 2 # :nodoc:
  1613.       end
  1614.  
  1615.       ##
  1616.       # The canonical name for an alias.
  1617.  
  1618.       class CNAME < DomainName
  1619.         TypeValue = 5 # :nodoc:
  1620.       end
  1621.  
  1622.       ##
  1623.       # Start Of Authority resource.
  1624.  
  1625.       class SOA < Resource
  1626.  
  1627.         TypeValue = 6 # :nodoc:
  1628.  
  1629.         ##
  1630.         # Creates a new SOA record.  See the attr documentation for the
  1631.         # details of each argument.
  1632.  
  1633.         def initialize(mname, rname, serial, refresh, retry_, expire, minimum)
  1634.           @mname = mname
  1635.           @rname = rname
  1636.           @serial = serial
  1637.           @refresh = refresh
  1638.           @retry = retry_
  1639.           @expire = expire
  1640.           @minimum = minimum
  1641.         end
  1642.  
  1643.         ##
  1644.         # Name of the host where the master zone file for this zone resides.
  1645.  
  1646.         attr_reader :mname
  1647.  
  1648.         ##
  1649.         # The person responsible for this domain name.
  1650.  
  1651.         attr_reader :rname
  1652.  
  1653.         ##
  1654.         # The version number of the zone file.
  1655.  
  1656.         attr_reader :serial
  1657.  
  1658.         ##
  1659.         # How often, in seconds, a secondary name server is to check for
  1660.         # updates from the primary name server.
  1661.  
  1662.         attr_reader :refresh
  1663.  
  1664.         ##
  1665.         # How often, in seconds, a secondary name server is to retry after a
  1666.         # failure to check for a refresh.
  1667.  
  1668.         attr_reader :retry
  1669.  
  1670.         ##
  1671.         # Time in seconds that a secondary name server is to use the data
  1672.         # before refreshing from the primary name server.
  1673.  
  1674.         attr_reader :expire
  1675.  
  1676.         ##
  1677.         # The minimum number of seconds to be used for TTL values in RRs.
  1678.  
  1679.         attr_reader :minimum
  1680.  
  1681.         def encode_rdata(msg) # :nodoc:
  1682.           msg.put_name(@mname)
  1683.           msg.put_name(@rname)
  1684.           msg.put_pack('NNNNN', @serial, @refresh, @retry, @expire, @minimum)
  1685.         end
  1686.  
  1687.         def self.decode_rdata(msg) # :nodoc:
  1688.           mname = msg.get_name
  1689.           rname = msg.get_name
  1690.           serial, refresh, retry_, expire, minimum = msg.get_unpack('NNNNN')
  1691.           return self.new(
  1692.             mname, rname, serial, refresh, retry_, expire, minimum)
  1693.         end
  1694.       end
  1695.  
  1696.       ##
  1697.       # A Pointer to another DNS name.
  1698.  
  1699.       class PTR < DomainName
  1700.         TypeValue = 12 # :nodoc:
  1701.       end
  1702.  
  1703.       ##
  1704.       # Host Information resource.
  1705.  
  1706.       class HINFO < Resource
  1707.  
  1708.         TypeValue = 13 # :nodoc:
  1709.  
  1710.         ##
  1711.         # Creates a new HINFO running +os+ on +cpu+.
  1712.  
  1713.         def initialize(cpu, os)
  1714.           @cpu = cpu
  1715.           @os = os
  1716.         end
  1717.  
  1718.         ##
  1719.         # CPU architecture for this resource.
  1720.  
  1721.         attr_reader :cpu
  1722.  
  1723.         ##
  1724.         # Operating system for this resource.
  1725.  
  1726.         attr_reader :os
  1727.  
  1728.         def encode_rdata(msg) # :nodoc:
  1729.           msg.put_string(@cpu)
  1730.           msg.put_string(@os)
  1731.         end
  1732.  
  1733.         def self.decode_rdata(msg) # :nodoc:
  1734.           cpu = msg.get_string
  1735.           os = msg.get_string
  1736.           return self.new(cpu, os)
  1737.         end
  1738.       end
  1739.  
  1740.       ##
  1741.       # Mailing list or mailbox information.
  1742.  
  1743.       class MINFO < Resource
  1744.  
  1745.         TypeValue = 14 # :nodoc:
  1746.  
  1747.         def initialize(rmailbx, emailbx)
  1748.           @rmailbx = rmailbx
  1749.           @emailbx = emailbx
  1750.         end
  1751.  
  1752.         ##
  1753.         # Domain name responsible for this mail list or mailbox.
  1754.  
  1755.         attr_reader :rmailbx
  1756.  
  1757.         ##
  1758.         # Mailbox to use for error messages related to the mail list or mailbox.
  1759.  
  1760.         attr_reader :emailbx
  1761.  
  1762.         def encode_rdata(msg) # :nodoc:
  1763.           msg.put_name(@rmailbx)
  1764.           msg.put_name(@emailbx)
  1765.         end
  1766.  
  1767.         def self.decode_rdata(msg) # :nodoc:
  1768.           rmailbx = msg.get_string
  1769.           emailbx = msg.get_string
  1770.           return self.new(rmailbx, emailbx)
  1771.         end
  1772.       end
  1773.  
  1774.       ##
  1775.       # Mail Exchanger resource.
  1776.  
  1777.       class MX < Resource
  1778.  
  1779.         TypeValue= 15 # :nodoc:
  1780.  
  1781.         ##
  1782.         # Creates a new MX record with +preference+, accepting mail at
  1783.         # +exchange+.
  1784.  
  1785.         def initialize(preference, exchange)
  1786.           @preference = preference
  1787.           @exchange = exchange
  1788.         end
  1789.  
  1790.         ##
  1791.         # The preference for this MX.
  1792.  
  1793.         attr_reader :preference
  1794.  
  1795.         ##
  1796.         # The host of this MX.
  1797.  
  1798.         attr_reader :exchange
  1799.  
  1800.         def encode_rdata(msg) # :nodoc:
  1801.           msg.put_pack('n', @preference)
  1802.           msg.put_name(@exchange)
  1803.         end
  1804.  
  1805.         def self.decode_rdata(msg) # :nodoc:
  1806.           preference, = msg.get_unpack('n')
  1807.           exchange = msg.get_name
  1808.           return self.new(preference, exchange)
  1809.         end
  1810.       end
  1811.  
  1812.       ##
  1813.       # Unstructured text resource.
  1814.  
  1815.       class TXT < Resource
  1816.  
  1817.         TypeValue = 16 # :nodoc:
  1818.  
  1819.         def initialize(first_string, *rest_strings)
  1820.           @strings = [first_string, *rest_strings]
  1821.         end
  1822.  
  1823.         ##
  1824.         # Returns an Array of Strings for this TXT record.
  1825.  
  1826.         attr_reader :strings
  1827.  
  1828.         ##
  1829.         # Returns the first string from +strings+.
  1830.  
  1831.         def data
  1832.           @strings[0]
  1833.         end
  1834.  
  1835.         def encode_rdata(msg) # :nodoc:
  1836.           msg.put_string_list(@strings)
  1837.         end
  1838.  
  1839.         def self.decode_rdata(msg) # :nodoc:
  1840.           strings = msg.get_string_list
  1841.           return self.new(*strings)
  1842.         end
  1843.       end
  1844.  
  1845.       ##
  1846.       # A Query type requesting any RR.
  1847.  
  1848.       class ANY < Query
  1849.         TypeValue = 255 # :nodoc:
  1850.       end
  1851.  
  1852.       ClassInsensitiveTypes = [ # :nodoc:
  1853.         NS, CNAME, SOA, PTR, HINFO, MINFO, MX, TXT, ANY
  1854.       ]
  1855.  
  1856.       ##
  1857.       # module IN contains ARPA Internet specific RRs.
  1858.  
  1859.       module IN
  1860.  
  1861.         ClassValue = 1 # :nodoc:
  1862.  
  1863.         ClassInsensitiveTypes.each {|s|
  1864.           c = Class.new(s)
  1865.           c.const_set(:TypeValue, s::TypeValue)
  1866.           c.const_set(:ClassValue, ClassValue)
  1867.           ClassHash[[s::TypeValue, ClassValue]] = c
  1868.           self.const_set(s.name.sub(/.*::/, ''), c)
  1869.         }
  1870.  
  1871.         ##
  1872.         # IPv4 Address resource
  1873.  
  1874.         class A < Resource
  1875.           TypeValue = 1
  1876.           ClassValue = IN::ClassValue
  1877.           ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
  1878.  
  1879.           ##
  1880.           # Creates a new A for +address+.
  1881.  
  1882.           def initialize(address)
  1883.             @address = IPv4.create(address)
  1884.           end
  1885.  
  1886.           ##
  1887.           # The Resolv::IPv4 address for this A.
  1888.  
  1889.           attr_reader :address
  1890.  
  1891.           def encode_rdata(msg) # :nodoc:
  1892.             msg.put_bytes(@address.address)
  1893.           end
  1894.  
  1895.           def self.decode_rdata(msg) # :nodoc:
  1896.             return self.new(IPv4.new(msg.get_bytes(4)))
  1897.           end
  1898.         end
  1899.  
  1900.         ##
  1901.         # Well Known Service resource.
  1902.  
  1903.         class WKS < Resource
  1904.           TypeValue = 11
  1905.           ClassValue = IN::ClassValue
  1906.           ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
  1907.  
  1908.           def initialize(address, protocol, bitmap)
  1909.             @address = IPv4.create(address)
  1910.             @protocol = protocol
  1911.             @bitmap = bitmap
  1912.           end
  1913.  
  1914.           ##
  1915.           # The host these services run on.
  1916.  
  1917.           attr_reader :address
  1918.  
  1919.           ##
  1920.           # IP protocol number for these services.
  1921.  
  1922.           attr_reader :protocol
  1923.  
  1924.           ##
  1925.           # A bit map of enabled services on this host.
  1926.           #
  1927.           # If protocol is 6 (TCP) then the 26th bit corresponds to the SMTP
  1928.           # service (port 25).  If this bit is set, then an SMTP server should
  1929.           # be listening on TCP port 25; if zero, SMTP service is not
  1930.           # supported.
  1931.  
  1932.           attr_reader :bitmap
  1933.  
  1934.           def encode_rdata(msg) # :nodoc:
  1935.             msg.put_bytes(@address.address)
  1936.             msg.put_pack("n", @protocol)
  1937.             msg.put_bytes(@bitmap)
  1938.           end
  1939.  
  1940.           def self.decode_rdata(msg) # :nodoc:
  1941.             address = IPv4.new(msg.get_bytes(4))
  1942.             protocol, = msg.get_unpack("n")
  1943.             bitmap = msg.get_bytes
  1944.             return self.new(address, protocol, bitmap)
  1945.           end
  1946.         end
  1947.  
  1948.         ##
  1949.         # An IPv6 address record.
  1950.  
  1951.         class AAAA < Resource
  1952.           TypeValue = 28
  1953.           ClassValue = IN::ClassValue
  1954.           ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
  1955.  
  1956.           ##
  1957.           # Creates a new AAAA for +address+.
  1958.  
  1959.           def initialize(address)
  1960.             @address = IPv6.create(address)
  1961.           end
  1962.           
  1963.           ##
  1964.           # The Resolv::IPv6 address for this AAAA.
  1965.  
  1966.           attr_reader :address
  1967.  
  1968.           def encode_rdata(msg) # :nodoc:
  1969.             msg.put_bytes(@address.address)
  1970.           end
  1971.  
  1972.           def self.decode_rdata(msg) # :nodoc:
  1973.             return self.new(IPv6.new(msg.get_bytes(16)))
  1974.           end
  1975.         end
  1976.  
  1977.         ##
  1978.         # SRV resource record defined in RFC 2782
  1979.         # 
  1980.         # These records identify the hostname and port that a service is
  1981.         # available at.
  1982.  
  1983.         class SRV < Resource
  1984.           TypeValue = 33
  1985.           ClassValue = IN::ClassValue
  1986.           ClassHash[[TypeValue, ClassValue]] = self # :nodoc:
  1987.  
  1988.           # Create a SRV resource record.
  1989.           #
  1990.           # See the documentation for #priority, #weight, #port and #target
  1991.           # for +priority+, +weight+, +port and +target+ respectively.
  1992.  
  1993.           def initialize(priority, weight, port, target)
  1994.             @priority = priority.to_int
  1995.             @weight = weight.to_int
  1996.             @port = port.to_int
  1997.             @target = Name.create(target)
  1998.           end
  1999.  
  2000.           # The priority of this target host.
  2001.           #
  2002.           # A client MUST attempt to contact the target host with the
  2003.           # lowest-numbered priority it can reach; target hosts with the same
  2004.           # priority SHOULD be tried in an order defined by the weight field.
  2005.           # The range is 0-65535.  Note that it is not widely implemented and
  2006.           # should be set to zero.
  2007.  
  2008.           attr_reader :priority
  2009.  
  2010.           # A server selection mechanism.
  2011.           #
  2012.           # The weight field specifies a relative weight for entries with the
  2013.           # same priority. Larger weights SHOULD be given a proportionately
  2014.           # higher probability of being selected. The range of this number is
  2015.           # 0-65535.  Domain administrators SHOULD use Weight 0 when there
  2016.           # isn't any server selection to do, to make the RR easier to read
  2017.           # for humans (less noisy). Note that it is not widely implemented
  2018.           # and should be set to zero.
  2019.  
  2020.           attr_reader :weight
  2021.  
  2022.           # The port on this target host of this service.
  2023.           #
  2024.           # The range is 0-65535.
  2025.  
  2026.           attr_reader :port
  2027.  
  2028.           # The domain name of the target host.
  2029.           #
  2030.           # A target of "." means that the service is decidedly not available
  2031.           # at this domain.
  2032.  
  2033.           attr_reader :target
  2034.  
  2035.           def encode_rdata(msg) # :nodoc:
  2036.             msg.put_pack("n", @priority)
  2037.             msg.put_pack("n", @weight)
  2038.             msg.put_pack("n", @port)
  2039.             msg.put_name(@target)
  2040.           end
  2041.  
  2042.           def self.decode_rdata(msg) # :nodoc:
  2043.             priority, = msg.get_unpack("n")
  2044.             weight,   = msg.get_unpack("n")
  2045.             port,     = msg.get_unpack("n")
  2046.             target    = msg.get_name
  2047.             return self.new(priority, weight, port, target)
  2048.           end
  2049.         end
  2050.       end
  2051.     end
  2052.   end
  2053.  
  2054.   ##
  2055.   # A Resolv::DNS IPv4 address.
  2056.  
  2057.   class IPv4
  2058.  
  2059.     ##
  2060.     # Regular expression IPv4 addresses must match.
  2061.  
  2062.     Regex = /\A(\d+)\.(\d+)\.(\d+)\.(\d+)\z/
  2063.  
  2064.     def self.create(arg)
  2065.       case arg
  2066.       when IPv4
  2067.         return arg
  2068.       when Regex
  2069.         if (0..255) === (a = $1.to_i) &&
  2070.            (0..255) === (b = $2.to_i) &&
  2071.            (0..255) === (c = $3.to_i) &&
  2072.            (0..255) === (d = $4.to_i)
  2073.           return self.new([a, b, c, d].pack("CCCC"))
  2074.         else
  2075.           raise ArgumentError.new("IPv4 address with invalid value: " + arg)
  2076.         end
  2077.       else
  2078.         raise ArgumentError.new("cannot interpret as IPv4 address: #{arg.inspect}")
  2079.       end
  2080.     end
  2081.  
  2082.     def initialize(address) # :nodoc:
  2083.       unless address.kind_of?(String) && address.length == 4
  2084.         raise ArgumentError.new('IPv4 address must be 4 bytes')
  2085.       end
  2086.       @address = address
  2087.     end
  2088.  
  2089.     ##
  2090.     # A String representation of this IPv4 address.
  2091.  
  2092.     ##
  2093.     # The raw IPv4 address as a String.
  2094.  
  2095.     attr_reader :address
  2096.  
  2097.     def to_s # :nodoc:
  2098.       return sprintf("%d.%d.%d.%d", *@address.unpack("CCCC"))
  2099.     end
  2100.  
  2101.     def inspect # :nodoc:
  2102.       return "#<#{self.class} #{self.to_s}>"
  2103.     end
  2104.  
  2105.     ##
  2106.     # Turns this IPv4 address into a Resolv::DNS::Name.
  2107.  
  2108.     def to_name
  2109.       return DNS::Name.create(
  2110.         '%d.%d.%d.%d.in-addr.arpa.' % @address.unpack('CCCC').reverse)
  2111.     end
  2112.  
  2113.     def ==(other) # :nodoc:
  2114.       return @address == other.address
  2115.     end
  2116.  
  2117.     def eql?(other) # :nodoc:
  2118.       return self == other
  2119.     end
  2120.  
  2121.     def hash # :nodoc:
  2122.       return @address.hash
  2123.     end
  2124.   end
  2125.  
  2126.   ##
  2127.   # A Resolv::DNS IPv6 address.
  2128.  
  2129.   class IPv6
  2130.  
  2131.     ##
  2132.     # IPv6 address format a:b:c:d:e:f:g:h
  2133.     Regex_8Hex = /\A
  2134.       (?:[0-9A-Fa-f]{1,4}:){7}
  2135.          [0-9A-Fa-f]{1,4}
  2136.       \z/x
  2137.  
  2138.     ##
  2139.     # Compressed IPv6 address format a::b
  2140.  
  2141.     Regex_CompressedHex = /\A
  2142.       ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) ::
  2143.       ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)
  2144.       \z/x
  2145.  
  2146.     ##
  2147.     # IPv4 mapped IPv6 address format a:b:c:d:e:f:w.x.y.z
  2148.  
  2149.     Regex_6Hex4Dec = /\A
  2150.       ((?:[0-9A-Fa-f]{1,4}:){6,6})
  2151.       (\d+)\.(\d+)\.(\d+)\.(\d+)
  2152.       \z/x
  2153.  
  2154.     ##
  2155.     # Compressed IPv4 mapped IPv6 address format a::b:w.x.y.z
  2156.  
  2157.     Regex_CompressedHex4Dec = /\A
  2158.       ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) ::
  2159.       ((?:[0-9A-Fa-f]{1,4}:)*)
  2160.       (\d+)\.(\d+)\.(\d+)\.(\d+)
  2161.       \z/x
  2162.  
  2163.     ##
  2164.     # A composite IPv6 address Regexp.
  2165.  
  2166.     Regex = /
  2167.       (?:#{Regex_8Hex}) |
  2168.       (?:#{Regex_CompressedHex}) |
  2169.       (?:#{Regex_6Hex4Dec}) |
  2170.       (?:#{Regex_CompressedHex4Dec})/x
  2171.  
  2172.     ##
  2173.     # Creates a new IPv6 address from +arg+ which may be:
  2174.     #
  2175.     # IPv6:: returns +arg+.
  2176.     # String:: +arg+ must match one of the IPv6::Regex* constants
  2177.  
  2178.     def self.create(arg)
  2179.       case arg
  2180.       when IPv6
  2181.         return arg
  2182.       when String
  2183.         address = ''
  2184.         if Regex_8Hex =~ arg
  2185.           arg.scan(/[0-9A-Fa-f]+/) {|hex| address << [hex.hex].pack('n')}
  2186.         elsif Regex_CompressedHex =~ arg
  2187.           prefix = $1
  2188.           suffix = $2
  2189.           a1 = ''
  2190.           a2 = ''
  2191.           prefix.scan(/[0-9A-Fa-f]+/) {|hex| a1 << [hex.hex].pack('n')}
  2192.           suffix.scan(/[0-9A-Fa-f]+/) {|hex| a2 << [hex.hex].pack('n')}
  2193.           omitlen = 16 - a1.length - a2.length
  2194.           address << a1 << "\0" * omitlen << a2
  2195.         elsif Regex_6Hex4Dec =~ arg
  2196.           prefix, a, b, c, d = $1, $2.to_i, $3.to_i, $4.to_i, $5.to_i
  2197.           if (0..255) === a && (0..255) === b && (0..255) === c && (0..255) === d
  2198.             prefix.scan(/[0-9A-Fa-f]+/) {|hex| address << [hex.hex].pack('n')}
  2199.             address << [a, b, c, d].pack('CCCC')
  2200.           else
  2201.             raise ArgumentError.new("not numeric IPv6 address: " + arg)
  2202.           end
  2203.         elsif Regex_CompressedHex4Dec =~ arg
  2204.           prefix, suffix, a, b, c, d = $1, $2, $3.to_i, $4.to_i, $5.to_i, $6.to_i
  2205.           if (0..255) === a && (0..255) === b && (0..255) === c && (0..255) === d
  2206.             a1 = ''
  2207.             a2 = ''
  2208.             prefix.scan(/[0-9A-Fa-f]+/) {|hex| a1 << [hex.hex].pack('n')}
  2209.             suffix.scan(/[0-9A-Fa-f]+/) {|hex| a2 << [hex.hex].pack('n')}
  2210.             omitlen = 12 - a1.length - a2.length
  2211.             address << a1 << "\0" * omitlen << a2 << [a, b, c, d].pack('CCCC')
  2212.           else
  2213.             raise ArgumentError.new("not numeric IPv6 address: " + arg)
  2214.           end
  2215.         else
  2216.           raise ArgumentError.new("not numeric IPv6 address: " + arg)
  2217.         end
  2218.         return IPv6.new(address)
  2219.       else
  2220.         raise ArgumentError.new("cannot interpret as IPv6 address: #{arg.inspect}")
  2221.       end
  2222.     end
  2223.  
  2224.     def initialize(address) # :nodoc:
  2225.       unless address.kind_of?(String) && address.length == 16
  2226.         raise ArgumentError.new('IPv6 address must be 16 bytes')
  2227.       end
  2228.       @address = address
  2229.     end
  2230.  
  2231.     ##
  2232.     # The raw IPv6 address as a String.
  2233.  
  2234.     attr_reader :address
  2235.  
  2236.     def to_s # :nodoc:
  2237.       address = sprintf("%X:%X:%X:%X:%X:%X:%X:%X", *@address.unpack("nnnnnnnn"))
  2238.       unless address.sub!(/(^|:)0(:0)+(:|$)/, '::')
  2239.         address.sub!(/(^|:)0(:|$)/, '::')
  2240.       end
  2241.       return address
  2242.     end
  2243.  
  2244.     def inspect # :nodoc:
  2245.       return "#<#{self.class} #{self.to_s}>"
  2246.     end
  2247.  
  2248.     ##
  2249.     # Turns this IPv6 address into a Resolv::DNS::Name.
  2250.     #--
  2251.     # ip6.arpa should be searched too. [RFC3152]
  2252.  
  2253.     def to_name
  2254.       return DNS::Name.new(
  2255.         @address.unpack("H32")[0].split(//).reverse + ['ip6', 'arpa'])
  2256.     end
  2257.  
  2258.     def ==(other) # :nodoc:
  2259.       return @address == other.address
  2260.     end
  2261.  
  2262.     def eql?(other) # :nodoc:
  2263.       return self == other
  2264.     end
  2265.  
  2266.     def hash # :nodoc:
  2267.       return @address.hash
  2268.     end
  2269.   end
  2270.  
  2271.   ##
  2272.   # Default resolver to use for Resolv class methods.
  2273.  
  2274.   DefaultResolver = self.new
  2275.  
  2276.   ##
  2277.   # Address Regexp to use for matching IP addresses.
  2278.  
  2279.   AddressRegex = /(?:#{IPv4::Regex})|(?:#{IPv6::Regex})/
  2280.  
  2281. end
  2282.  
  2283.